#include "AssetPath.h"
#include "Reflection/Class.h"
#include "Object/NewObjectInner.h"
#include "Object/Object.h"
#include "Object/RootObject.h"
#include "Object/ObjectPathUtils.h"

SAssetPath::SAssetPath(const CString& InPath)
{
    Initialize(InPath);
}

SAssetPath::SAssetPath(
    CClass *InAssetType
    , const CString &InPackageName
    , const CString &InFolderPathInPackage
    , const CString &InAssetName
   )
:AssetType(InAssetType)
,PackageName(InPackageName)
,FolderPathInPackage(InFolderPathInPackage)
,AssetName(InAssetName)
{
}

CString SAssetPath::AbstractFolderPathInPackage(const SPath &InPackageFolderPath, const SPath &InAssetFilePath)
{
    return InAssetFilePath.Parent().GetRelativeTo(InPackageFolderPath).ToString();
}

CString SAssetPath::AbstractAssetName(const SPath &InAssetFilePath)
{
    return InAssetFilePath.GetBaseFileName();
}

SAssetPath SAssetPath::CreateFrom(const CString &InObjectPath)
{
    auto AssetObjectName = WH::GetAssetObjectPath(InObjectPath);;

    //splite path by AssetPathSeparator
    //first part is class name
    //second part is package name
    //third part is path in package
    //fourth part is asset name
    auto AssetObjectParts = AssetObjectName.Split(WH::AssetPathSeparator);

    if (AssetObjectParts.size() < 4)
    {
        assert(false && "invalid asset object name");
        return SAssetPath();
    }

    auto AssetType = reinterpret_cast<CClass*>(CType::FindType(AssetObjectParts[0]));
    assert(AssetType && "invalid asset type");

    auto PackageName = AssetObjectParts[1];

    auto FolderPathInPackage = AssetObjectParts[2];

    auto AssetName = AssetObjectParts[3];

    return SAssetPath(AssetType, PackageName, FolderPathInPackage, AssetName);
}

void SAssetPath::Initialize(const CString &InStringExpression)
{
    //splite path by ' '
    //first part is Class name
    //second part is package name
    //third part is path in package
    //fourth part is guid

    auto Parts = InStringExpression.Split(WH::AssetPathSeparator);

    if (Parts.size() < 3)
    {
        assert(false && "invalid asset path");
        return;
    }

    AssetType=reinterpret_cast<CClass*>(CType::FindType(Parts[0]));
    assert(AssetType && "invalid asset type");

    PackageName = Parts[1];

    FolderPathInPackage = Parts[2];

    AssetName = Parts[3];
}

SAssetPath &SAssetPath::operator=(const SAssetPath &InOther)
{
    //check self assignment
    if (this == &InOther)
    {
        return *this;
    }

    AssetType = InOther.AssetType;
    PackageName = InOther.PackageName;
    FolderPathInPackage = InOther.FolderPathInPackage;
    AssetName = InOther.AssetName;

    return *this;
}

CString SAssetPath::ToString() const
{
    CString Result=
        AssetType->GetFullName() + WH::AssetPathSeparator 
        + PackageName +WH::AssetPathSeparator 
        + FolderPathInPackage + WH::AssetPathSeparator 
        + AssetName ;

    return Result;

}

CString SAssetPath::GetPackageName() const
{
    return PackageName;
}

void SAssetPath::SetAssetName(const CString &InAssetName)
{
    AssetName = InAssetName;
}

CString SAssetPath::GetFolderPathInPackage() const
{
    return FolderPathInPackage;
}

void SAssetPath::SetFolderPathInPackage(const CString &InFolderPathInPackage)
{
    FolderPathInPackage = InFolderPathInPackage;
}

TVector<CString> SAssetPath::GetFolderPathInPackageAsArray() const
{
    TVector<CString> Result=FolderPathInPackage.Split(U'/');
    
    //remove empty string and "."
    Result.RemoveBy([](const CString& InString) -> bool
    {
        return InString.IsEmpty() || InString == U".";
    });

    return Result;
}

uint64_t SAssetPath::GetHashCode() const
{
    return ToString().GetHashCode();
}

bool SAssetPath::operator==(const SAssetPath &Other) const
{
    return ToString() == Other.ToString();
}
